package cs2340.todolist.model.utility;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import android.content.Context;
import android.location.Location;

import com.google.android.maps.GeoPoint;

import cs2340.todolist.model.ToDoItem;
import cs2340.todolist.model.account_management.ToDoItemManager;

public class SearchEngine {
	

	public static interface Filter {
		void filter(Collection<ToDoItem> items);
	}
	
	public static class CombinedFilter implements Filter {
		List<Filter> filterList;
		
		public CombinedFilter() {
			filterList = new ArrayList<Filter>();
		}
		
		public void add(Filter filter) {
			filterList.add(filter);
		}
		
		/**
		 * filter using all the filtering engine currently in this CombinedFilter
		 */
		public void filter(Collection<ToDoItem> items) {
			for(Filter filter : filterList) {
				filter.filter(items);
			}
			
		}
		
	}
	
	
	public static class NullFilter implements Filter {

		/**
		 * filters nothing
		 * @param items
		 */
		public void filter(Collection<ToDoItem> items) {
			
		}

	
	}
	
	public static class FilterCompleted implements Filter {
		
		/**
		 * filters the input array by completedness based on filter
		 * @param array - the array to be filtered
		 */
		public void filter(Collection<ToDoItem> items) {
			Iterator<ToDoItem> itemIter = items.iterator();
			while(itemIter.hasNext()) {
				if(itemIter.next().getCompleted())
					itemIter.remove();
			}
			
		}

	}
	
	public static class FilterDate implements Filter {
		Date date;
		
		public FilterDate(Date date) {
			this.date = date;
		}
		
		/**
		 * filters the input array by date using the input filter
		 * @param items - the array to be filtered
		 */
		public void filter(Collection<ToDoItem> items) {
			Iterator<ToDoItem> itemIter = items.iterator();
			//for every item in the array, if it is past the input date filter, remove it
			while(itemIter.hasNext()) {
				if(itemIter.next().getDueDate().compareTo(date) > 0) {
					itemIter.remove();
				}
			}
			
		}

	}
	
	public static class FilterType implements Filter {
		int typeIndex;
		public FilterType(int typeIndex) {
			this.typeIndex = typeIndex;
		}
		

		/**
		 * filters the input array by the type of item it contains
		 * @param items - the array to be filtered
		 */
		public void filter(Collection<ToDoItem> items) {
			Iterator<ToDoItem> itemIter = items.iterator();

			while(itemIter.hasNext()) {	
				if(!itemIter.next().getType().equals(ToDoItemManager.TYPES[typeIndex])) {
					itemIter.remove();
				}
			}
		}
	}
	
	public static class FilterNearLocation implements Filter {
		Context context;
		GeoPoint pivot;
		int range;
		/**
		 * @param context
		 * @param pivot
		 * @param range in miles
		 * 
		 */
		public FilterNearLocation(Context context, GeoPoint pivot, int range) {
			this.context = context;
			this.pivot = pivot;
			this.range = range;
		}
		
		/**
		 * filter the items based on proximity to the pivot GeoPoint
		 * @param items
		 */
		public void filter(Collection<ToDoItem> items) {
			Iterator<ToDoItem> itemIter = items.iterator();
			while(itemIter.hasNext()) {
				GeoPoint geoPoint = itemIter.next().getLocation().geocode(context);
				if(distance(pivot, geoPoint) > range);
					itemIter.remove();
			}
			
		}
		

		 
	   public static double distance(GeoPoint StartP, GeoPoint EndP) {
	 
	      double lat1 = StartP.getLatitudeE6()/1E6;
	      double lat2 = EndP.getLatitudeE6()/1E6;
	      double lon1 = StartP.getLongitudeE6()/1E6;
	      double lon2 = EndP.getLongitudeE6()/1E6;
	      double dLat = Math.toRadians(lat2-lat1);
	      double dLon = Math.toRadians(lon2-lon1);
	 
	      double a = Math.sin(dLat/2) * Math.sin(dLat/2) +
	    		  	Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) *
	    		  	Math.sin(dLon/2) * Math.sin(dLon/2);
	 
	      double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
	 
	      return 3959 * c;
	 
	   }
		 

	}
}
